package com.neusoft.neuiotms.dcam.fixed.service.impl;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;

import com.google.common.collect.Lists;
import com.google.zxing.WriterException;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.bizcore.web.utils.EasyPoiExcelUtil;
import com.neusoft.bizcore.web.utils.EasyPoiStylerColorImpl;
import com.neusoft.neuiotms.common.dto.DictionaryDTO;
import com.neusoft.neuiotms.common.service.DictionaryService;
import com.neusoft.neuiotms.dcam.common.dto.DcamInstitutionsDTO;
import com.neusoft.neuiotms.dcam.common.service.DcamInstitutionsService;
import com.neusoft.neuiotms.dcam.config.QRCodeConfig;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.converter.AssetConverter;
import com.neusoft.neuiotms.dcam.fixed.converter.AssetLifeCycleConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetAttachmentDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetDTO;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.model.AssetAttachment;
import com.neusoft.neuiotms.dcam.fixed.model.AssetLifeCycle;
import com.neusoft.neuiotms.dcam.fixed.model.AssetType;
import com.neusoft.neuiotms.dcam.fixed.model.Contract;
import com.neusoft.neuiotms.dcam.fixed.model.Product;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetAttachmentRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetLifeCycleRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetTypeRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.ContractRepository;
import com.neusoft.neuiotms.dcam.fixed.service.AssetService;
import com.neusoft.neuiotms.dcam.fixed.util.SendingMessage;
import com.neusoft.neuiotms.dcam.fixed.vo.AssetExportVO;
import com.neusoft.neuiotms.dcam.fixed.vo.AssetImportVO;
import com.neusoft.neuiotms.dcam.util.PDFUtil;
import com.neusoft.neuiotms.dcam.util.PermUtils;
import com.neusoft.neuiotms.dcam.util.QRCodeMaker;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class AssetServiceImpl implements AssetService {

    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private AssetConverter assetConventer;
    @Autowired
    private AssetTypeRepository assetTypeRepository;
    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private SendingMessage sendingMessage;

    @Autowired
    private DcamInstitutionsService dcamInstitutionsService;

    @Autowired
    private QRCodeConfig qrCodeConfig;

    @Autowired
    private QRCodeMaker qrCodeMaker;
    @Autowired
    private AssetAttachmentRepository assetAttachmentRepository;

    @Autowired
    private AssetLifeCycleConverter assetLifeCycleConverter;
    @Autowired
    private AssetLifeCycleRepository assetLifeCycleRepository;

    @Override
    public List<AssetDTO> findAll(final Searchable searchable) {
        final List<Asset> asset = this.assetRepository.search(searchable);
        final List<AssetDTO> assetDtos = this.assetConventer.toListDTO(asset);
        return assetDtos;
    }

    @Override
    public Long count(final Searchable searchable) {
        return this.assetRepository.count(searchable);
    }

    @Override
    public Page<AssetDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<Asset> models = this.assetRepository.search(pageable, searchable);
        return this.assetConventer.toPageDTO(models);
    }

    @Override
    public AssetDTO details(final Long id) {
        final Asset model;
        try {
            model = this.assetRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, id);
        }
        return this.assetConventer.toDTO(model, false);
    }

    @Override
    public AssetDTO create(final AssetDTO dto) {
        final Asset check = this.assetRepository.findByCode(dto.getCode());
        if (check != null) {
            throw new UnitedException("资产编码不能重复", new Object[] {});
        }
        final Asset model = this.assetConventer.toModel(dto);

        this.assetRepository.save(model);
        return this.assetConventer.toDTO(model);
    }

    @Override
    public AssetDTO update(final Long id, final AssetDTO dto) {
        Asset model;
        try {
            model = this.assetRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, id);
        }

        final Asset check = this.assetRepository.findByCode(dto.getCode());
        if ((check != null) && (check.getId().longValue() != id.longValue())) {
            throw new UnitedException("资产编码不能重复", new Object[] {});
        }

        dto.setId(model.getId());
        model = this.assetConventer.toModel(dto);

        this.assetRepository.save(model);
        return this.assetConventer.toDTO(model);
    }

    @Override
    public void delete(final Long id) {
        try {
            this.assetRepository.deleteById(id);
        } catch (final Exception e) {
            AssetServiceImpl.log.error(e.getMessage(), e);
            throw new UnitedException("此资产已经产生业务，不能删除");
        }
    }

    @Override
    public void deleteBatch(final Long[] ids) {
        try {
            //            this.assetRepository.deleteByIdIn(new ArrayList<>(Arrays.asList(ids)));
            for (final Long id : ids) {
                this.assetRepository.deleteById(id);
            }
        } catch (final Exception e) {
            AssetServiceImpl.log.error(e.getMessage(), e);
            throw new UnitedException("部分资产已经产生业务，不能删除");
        }
    }

    @Override
    @Transactional
    public void upload(final InputStream fileStream, final String username) {
        AssetServiceImpl.log.info("assetService--------upload");
        final String title = "资产导入结果";
        final StringBuilder errorMsg = new StringBuilder();
        final ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        params.setNeedVerify(true);
        try {
            final ExcelImportResult<AssetImportVO> result =
                    ExcelImportUtil.importExcelMore(fileStream, AssetImportVO.class, params);
            if (result.getList().isEmpty() && result.getFailList().isEmpty()) {
                //                throw new UnitedException("上传数据为空", new Object[] {});
                AssetServiceImpl.log.error("资产导入上传数据为空");
                this.sendingMessage.SendImportResultToNotice(title, username, "上传数据为空");
                return;
            }
            if (result.isVerifyFail()) {
                final List<AssetImportVO> failList = result.getFailList();
                failList.forEach(l -> {
                    errorMsg.append("第" + (l.getRowNum() + 1) + "行," + l.getErrorMsg() + "! \n");
                });
            }
            if (errorMsg.length() > 0) {
                AssetServiceImpl.log.error(errorMsg.toString());
                //                throw new UnitedException(errorMsg.toString(), new Object[] {});
                this.sendingMessage.SendImportResultToNotice(title, username, errorMsg.toString());
                return;
            }

            final List<DictionaryDTO> source = this.dictionaryService.findByDictionaryType("assetSource");
            final Map<String, String> sourceMap =
                    source.stream().collect(Collectors.toMap(DictionaryDTO::getText, DictionaryDTO::getCode));
            final List<DictionaryDTO> status = this.dictionaryService.findByDictionaryType("assetStatus");
            final Map<String, String> statusMap =
                    status.stream().collect(Collectors.toMap(DictionaryDTO::getText, DictionaryDTO::getCode));
            final List<DictionaryDTO> useDept = this.dictionaryService.findByDictionaryType(DCAMConsts.ASSET_USE_DEPT);
            final Map<String, String> useDeptMap =
                    useDept.stream().collect(Collectors.toMap(DictionaryDTO::getText, DictionaryDTO::getCode));

            final List<DictionaryDTO> manageDept =
                    this.dictionaryService.findByDictionaryType(DCAMConsts.ASSET_MANAGE_DEPT);
            final Map<String, String> manageDeptMap =
                    manageDept.stream().collect(Collectors.toMap(DictionaryDTO::getText, DictionaryDTO::getCode));

            final List<DictionaryDTO> secondes =
                    this.dictionaryService.findByDictionaryType("secondDept");
            final Map<String, String> secondsMap =
                    secondes.stream().collect(Collectors.toMap(DictionaryDTO::getText, DictionaryDTO::getCode));

            //            final List<DictionaryDTO> thirds =
            //                    this.dictionaryService.findByDictionaryType("thirdDept");
            //            final Map<String, String> thirdsMap =
            //                    thirds.stream().collect(Collectors.toMap(DictionaryDTO::getText, DictionaryDTO::getCode));

            final List<Asset> models = new ArrayList<>();
            final List<AssetImportVO> saveList = result.getList();
            for (int i = 0; i < saveList.size(); i++) {
                final AssetImportVO asset = saveList.get(i);
                final Asset model = this.assetConventer.toModel(asset);
                if (!StringUtils.isEmpty(asset.getUseDeptDesc())) {
                    final String use_Dept = useDeptMap.get(asset.getUseDeptDesc());
                    if (StringUtils.isNotEmpty(use_Dept)) {
                        model.setUseDept(use_Dept);
                    } else {
                        this.sendingMessage.SendImportResultToNotice(title, username,
                                "第" + (i + 3) + "行," + "使用部门输入错误");
                        return;
                    }

                } else {
                    model.setUseDept(StringUtils.EMPTY);
                }
                if (StringUtils.isEmpty(asset.getCode())) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "资产编号不能为空!");
                    return;
                }
                if (StringUtils.isEmpty(asset.getAssetcategories())) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "资产大类不能为空!");
                    return;
                }
                if (StringUtils.isEmpty(asset.getName())) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "资产名称不能为空!");
                    return;
                }
                if (asset.getGetdate() == null) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "取得日期不能为空!");
                    return;
                }
                if (StringUtils.isEmpty(asset.getValuetype())) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "价值类型不能为空");
                    return;
                }
                if (StringUtils.isEmpty(asset.getMoney())) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "价值不能为空!");
                    return;
                } else {
                    if (model.getMoney().doubleValue() <= 0) {
                        this.sendingMessage.SendImportResultToNotice(title, username,
                                "第" + (i + 3) + "行," + "价值必须大于0!");
                        return;
                    }
                }
                if (StringUtils.isEmpty(asset.getStatusDesc())) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "使用状况不能为空!");
                    return;
                }
                if ((asset.getQuantity() == null) || asset.getQuantity().isNaN()
                        || (asset.getQuantity().doubleValue() == 0)) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "数量既不能为空也不能为零!");
                    return;
                } else {
                    if ((model.getQuantity() <= 0)
                            || ((model.getQuantity().intValue() - model.getQuantity().doubleValue()) != 0)) {
                        this.sendingMessage.SendImportResultToNotice(title, username,
                                "第" + (i + 3) + "行," + "数量必须大于零且不能有小数!");
                        return;
                    }
                }

                if (!StringUtils.isEmpty(asset.getManageDeptDesc())) {
                    final String assetManage = manageDeptMap.get(asset.getManageDeptDesc());
                    if (StringUtils.isNotEmpty(assetManage)) {
                        model.setManageDept(assetManage);
                    } else {
                        this.sendingMessage.SendImportResultToNotice(title, username,
                                "第" + (i + 3) + "行," + "管理部门输入错误");
                        return;
                    }
                } else {
                    model.setManageDept(StringUtils.EMPTY);
                }
                if (!StringUtils.isEmpty(asset.getSourceDesc())) {
                    final String sourceDesc = sourceMap.get(asset.getSourceDesc().trim());
                    if (StringUtils.isNotEmpty(sourceDesc)) {
                        model.setSource(sourceDesc);
                    } else {
                        this.sendingMessage.SendImportResultToNotice(title, username,
                                "第" + (i + 3) + "行," + "来源输入错误");
                        return;
                    }
                } else {
                    model.setSource(StringUtils.EMPTY);
                }
                if (!StringUtils.isEmpty(asset.getStatusDesc())) {
                    final String statusDesc = statusMap.get(asset.getStatusDesc().trim());
                    if (StringUtils.isNotEmpty(statusDesc)) {
                        model.setStatus(statusDesc);
                    } else {
                        this.sendingMessage.SendImportResultToNotice(title, username,
                                "第" + (i + 3) + "行," + "资产状况输入错误");
                        return;
                    }

                } else {
                    model.setStatus(StringUtils.EMPTY);
                }
                //类型
                if (!StringUtils.isEmpty(asset.getAssetTypeName())) {
                    try {
                        final String categories = asset.getAssetcategories();
                        final AssetType category = this.assetTypeRepository.findByName(categories);
                        //                        final String assetTypeName = asset.getAssetTypeName();
                        final List<AssetType> types = this.assetTypeRepository.findByParentId(category.getId());
                        final AssetType assetType = types.parallelStream()
                                .filter(r -> asset.getAssetTypeName().equals(r.getName())).findFirst().get();
                        if (assetType != null) {
                            model.setType(assetType);
                        } else {
                            AssetServiceImpl.log.error("第" + (i + 3) + "行," + "资产类型不存在");
                            this.sendingMessage.SendImportResultToNotice(title, username,
                                    "第" + (i + 3) + "行," + "资产类型不存在");
                            return;
                        }
                    } catch (final EntityNotFoundException e) {
                        //                        throw new UnitedException("第" + (i + 1) + "行," + "资产类型不存在", new Object[] {types[1] });
                        AssetServiceImpl.log.error("第" + (i + 3) + "行," + "资产类型不存在");
                        this.sendingMessage.SendImportResultToNotice(title, username, "第" + (i + 3) + "行," + "资产类型不存在");
                        return;
                    } catch (final Exception ex) {
                        this.sendingMessage.SendImportResultToNotice(title, username,
                                "第" + (i + 3) + "行," + "产品类型输入错误");
                        return;
                    }
                } else {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "产品小类不能为空");
                    return;
                }
                if (StringUtils.isEmpty(asset.getName())) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "资产名称不能为空");
                    return;
                }

                if (StringUtils.isEmpty(asset.getSubmmitto())) {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "移交厅局不能为空");
                    return;
                }
                // 价值类型
                if (!StringUtils.isEmpty(asset.getValuetype())) {
                    final List<DictionaryDTO> lstDis = this.dictionaryService.findByDictionaryType("valuetype");
                    if (lstDis != null) {
                        final DictionaryDTO dictionary = lstDis.parallelStream()
                                .filter(r -> r.getText().equals(asset.getValuetype())).findFirst().get();
                        if ((dictionary == null) || StringUtils.isEmpty(dictionary.getCode())) {
                            this.sendingMessage.SendImportResultToNotice(title, username,
                                    "第" + (i + 3) + "行," + "价值类型输入错误");
                            return;
                        } else {
                            model.setValuetype(dictionary.getCode());
                        }

                    }
                } else {
                    model.setValuetype(StringUtils.EMPTY);
                }
                // 二级移交单位
                if (!StringUtils.isEmpty(asset.getSecondDept())) {
                    final String secondDept = secondsMap.get(asset.getSecondDept());
                    if (StringUtils.isNotEmpty(secondDept)) {
                        model.setSecondeDept(secondDept);
                    } else {
                        this.sendingMessage.SendImportResultToNotice(title, username,
                                "第" + (i + 3) + "行," + "移交一级下属单位输入错误");
                        return;
                    }
                } else {
                    model.setSecondeDept(StringUtils.EMPTY);
                }
                // 三级单位
                //                if (!StringUtils.isEmpty(asset.getThirdDept())) {
                //                    final String thirdDept = thirdsMap.get(asset.getThirdDept());
                //                    if(StringUtils.isNotEmpty(thirdDept)){
                //                        model.setThirdDept(thirdDept);
                //                    }else{
                //                        this.sendingMessage.SendImportResultToNotice(title, username,
                //                                "第" + (i + 3) + "行," + "移交二级下属单位输入错误");
                //                        return;
                //                    }
                //                }else{
                //                    model.setThirdDept(StringUtils.EMPTY);
                //                }
                //资产编码
                if (!StringUtils.isEmpty(asset.getCode())) {
                    model.setCode(asset.getCode());
                } else {
                    this.sendingMessage.SendImportResultToNotice(title, username,
                            "第" + (i + 3) + "行," + "资产编码是必填项，请确认资产编码后提交！");
                    return;
                }
                models.add(model);
            }
            if (!models.isEmpty() && (errorMsg.length() == 0)) {
                this.assetRepository.saveAll(models);
                this.sendingMessage.SendImportResultToNotice(title, username, "资产上传成功");
            }

        } catch (final Exception e) {
            AssetServiceImpl.log.error("上传失败", e);
            this.sendingMessage.SendImportResultToNotice(title, username,
                    "上传失败" + (e instanceof DataIntegrityViolationException ? " ：重复记录" : e.getMessage()));
            throw new UnitedException(e.getMessage(), new Object[] {});
        }

    }

    @Override
    public Workbook export(final Searchable searchable, final Pageable pageable, UserBean userBean) {
        final List<DictionaryDTO> source = this.dictionaryService.findByDictionaryType(DCAMConsts.ASSET_SOURCE);
        final Map<String, String> sourceMap =
                source.stream().collect(Collectors.toMap(DictionaryDTO::getCode, DictionaryDTO::getText));
        final List<DictionaryDTO> status = this.dictionaryService.findByDictionaryType("assetStatus");
        final Map<String, String> statusMap =
                status.stream().collect(Collectors.toMap(DictionaryDTO::getCode, DictionaryDTO::getText));

        final List<Asset> models = this.assetRepository.search(searchable);
        final List<AssetExportVO> list = new ArrayList<>(models.size() == 0 ? 1 : models.size());
        final List<DictionaryDTO> useDept = this.dictionaryService.findByDictionaryType(DCAMConsts.ASSET_USE_DEPT);
        final Map<String, String> useDeptMap =
                useDept.stream().collect(Collectors.toMap(DictionaryDTO::getCode, DictionaryDTO::getText));

        final List<DictionaryDTO> manageDept =
                this.dictionaryService.findByDictionaryType(DCAMConsts.ASSET_MANAGE_DEPT);
        final Map<String, String> manageDeptMap =
                manageDept.stream().collect(Collectors.toMap(DictionaryDTO::getCode, DictionaryDTO::getText));

        final List<DictionaryDTO> secondes =
                this.dictionaryService.findByDictionaryType("secondDept");
        final Map<String, String> secondsMap =
                secondes.stream().collect(Collectors.toMap(DictionaryDTO::getCode, DictionaryDTO::getText));

        //        final List<DictionaryDTO> thirds =
        //                this.dictionaryService.findByDictionaryType("thirdDept");
        //        final Map<String, String> thirdsMap =
        //                thirds.stream().collect(Collectors.toMap(DictionaryDTO::getCode, DictionaryDTO::getText));

        models.forEach(model -> {
            final AssetExportVO vo = this.assetConventer.toVO(model);
            if (!StringUtils.isEmpty(vo.getSourceDesc())) {
                vo.setSourceDesc(sourceMap.get(vo.getSourceDesc()));
            }
            if (!StringUtils.isEmpty(vo.getStatusDesc())) {
                vo.setStatusDesc(statusMap.get(vo.getStatusDesc()));
            }
            if (!StringUtils.isEmpty(vo.getUseDeptDesc())) {
                vo.setUseDeptDesc(useDeptMap.get(vo.getUseDeptDesc().trim()));
            }
            if (!StringUtils.isEmpty(vo.getManageDeptDesc())) {
                vo.setManageDeptDesc(manageDeptMap.get(vo.getManageDeptDesc().trim()));
            }
            if (!StringUtils.isEmpty(model.getSecondeDept())) {
                vo.setSecondDept(secondsMap.get(model.getSecondeDept().trim()));
            }
            //            if (!StringUtils.isEmpty(model.getThirdDept())) {
            //                vo.setThirdDept(thirdsMap.get(model.getThirdDept().trim()));
            //            }

            list.add(vo);
        });

        final ExportParams param = new ExportParams("资产导出", "资产导出", ExcelType.XSSF);
        param.setStyle(EasyPoiStylerColorImpl.class);
        final Workbook workbook = ExcelExportUtil.exportExcel(param, AssetExportVO.class, list);

        final List<Map<String, Object>> constraint = this.getConstraint(userBean);
        // 级联Types

        final List<AssetType> allTypes = this.assetTypeRepository.findAll();
        final List<String> categories = new ArrayList<>();
        allTypes.forEach(l -> {
            if ((l.getParent() == null) || StringUtils.isEmpty(l.getParent().getName())) {
                categories.add(l.getName());
            }
        });

        final Map<String, List<String>> children = new HashMap<>();
        final List<AssetType> allType = this.assetTypeRepository.findAll().parallelStream()
                .filter(r -> r.getParent() != null).collect(Collectors.toList());
        allTypes.forEach(k -> {
            final List<AssetType> ll = allType.parallelStream().filter(r -> k.getId().equals(r.getParent().getId()))
                    .collect(Collectors.toList());
            final List<String> result = new ArrayList<>();
            ll.forEach(r -> {
                result.add(r.getName());
            });
            children.put(k.getName(), result);
        });
        final ArrayList<Integer> columns = Lists.newArrayList(DCAMConsts.ASSET_CONSTRAINT_CATEGORIED_COL,
                DCAMConsts.ASSET_CONSTRAINT_ASSET_TYPE_NAME_COL);
        EasyPoiExcelUtil.cascade(workbook, categories, categories,
                children,
                columns, 0, 1, DCAMConsts.ASSET_CONSTRAINT_ROW);

        EasyPoiExcelUtil.setConstraint(constraint, workbook, DCAMConsts.ASSET_START_CONSTRAINT_ROW,
                DCAMConsts.ASSET_CONSTRAINT_ROW);

        return workbook;
    }

    //位置下拉候选框数据
    private List<Map<String, Object>> getConstraint(final UserBean userBean) {
        final List<Map<String, Object>> constraint = new ArrayList<>();
        for (final String element : DCAMConsts.ASSET_EXPORT_CONSTRAINT) {
            final List<String> constraintList = new ArrayList<>();
            Integer col = 0;
            switch (element) {
            // 价值类型
            case DCAMConsts.ASSET_VALUE_TYPE_NAME_KEY:
                final List<DictionaryDTO> dictionaries = this.dictionaryService.findByDictionaryType("valuetype");
                dictionaries.stream().forEach(l -> {
                    constraintList.add(l.getText());
                });
                col = DCAMConsts.ASSET_CONSTRAINT_ASSET_VALUE_TYPE_COL;
                break;
            //合同下拉候选框
            case DCAMConsts.ASSET_CONTRACT_KEY:
                final List<Contract> contracts = this.contractRepository.findAll();
                contracts.stream().forEach(l -> {
                    constraintList.add(l.getName() + DCAMConsts.DICTIONARY_SPLITOR + l.getCode());
                });
                col = DCAMConsts.ASSET_CONSTRAINT_CONTRACT_COL;
                break;
            //资产来源候选框数据
            case DCAMConsts.ASSET_SOURCE:
                final List<DictionaryDTO> source = this.dictionaryService.findByDictionaryType("assetSource");
                source.forEach(t -> {
                    constraintList.add(t.getText());
                });
                col = DCAMConsts.ASSET_CONSTRAINT_SOURCE_COL;
                break;
            // 资产状态
            case DCAMConsts.ASSET_STATUS:
                final List<DictionaryDTO> status = this.dictionaryService.findByDictionaryType("assetStatus");
                status.forEach(t -> {
                    constraintList.add(t.getText());
                });
                col = DCAMConsts.ASSET_CONSTRAINT_STATUS_COL;
                break;
            // 使用部门
            case DCAMConsts.ASSET_USE_DEPT_KEY:
                final List<DictionaryDTO> useDepts = this.dictionaryService.findByDictionaryType("useDept");
                useDepts.forEach(t -> {
                    constraintList.add(t.getText());
                });
                col = DCAMConsts.ASSET_CONSTRAINT_USE_DEPT_COL;
                break;
            //使用人候选框数据
            case DCAMConsts.ASSET_MANAGE_DEPT:
                final List<DictionaryDTO> manageDept = this.dictionaryService.findByDictionaryType("manageDept");
                manageDept.forEach(t -> {
                    constraintList.add(t.getText());
                });
                col = DCAMConsts.ASSET_CONSTRAINT_MANAGE_DEPT_COL;
                break;
            case DCAMConsts.ASSET_SUBMMIT_TO_KEY:
                final List<DcamInstitutionsDTO> list = this.dcamInstitutionsService.getPermInstitutionsByCode(userBean);
                list.forEach(t -> {
                    constraintList.add(t.getName());
                });
                col = DCAMConsts.ASSET_SUBMMIT_TO_COL;
                break;
            //            // 文档是否齐全
            case DCAMConsts.ASSET_DOCUMENT_ALL_KEY:
                constraintList.add("是");
                constraintList.add("否");
                col = DCAMConsts.ASSET_CONSTRAINT_DOCUMENT_ALL_COL;
                break;
            case DCAMConsts.ASSET_RUNNING_KEY:
                constraintList.add("是");
                constraintList.add("否");
                col = DCAMConsts.ASSET_RUNNING_KEY_COL;
                break;
            //使用部门候选框数据
            case DCAMConsts.ASSET_SCRAPPED_KEY:

                constraintList.add("是");
                constraintList.add("否");
                col = DCAMConsts.ASSET_CONSTRAINT_SCRAPPED_COL;
                break;
            case DCAMConsts.ASSET_SECOND_DEPT_KEY:
                final List<DictionaryDTO> seconds = this.dictionaryService.findByDictionaryType("secondDept");
                seconds.stream().forEach(l -> {
                    constraintList.add(l.getText());
                });
                col = DCAMConsts.ASSET_SECONDE_DEPT_COL;
                break;
            //            case DCAMConsts.ASSET_THIRD_DEPT_KEY:
            //                final List<DictionaryDTO> third = this.dictionaryService.findByDictionaryType("thirdDept");
            //                third.stream().forEach(l -> {
            //                    constraintList.add(l.getText());
            //                });
            //                col = DCAMConsts.ASSET_THIRD_DEPT_COL;
            //                break;
            }

            if (!constraintList.isEmpty()) {
                final Map<String, Object> map = new HashMap<>();
                map.put("list", constraintList);
                map.put("col", col);
                constraint.add(map);
            }
        }
        return constraint;
    }

    @Override
    public Workbook template(final UserBean userBean) {
        final List<AssetImportVO> list = new ArrayList<>();
        final Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("资产导入模板", "资产导入模板", ExcelType.XSSF),
                AssetImportVO.class, list);

        final List<Map<String, Object>> constraint = this.getConstraint(userBean);
        // 级联Types

        final List<AssetType> allTypes = this.assetTypeRepository.findAll();
        final List<String> categories = new ArrayList<>();
        allTypes.forEach(l -> {
            if ((l.getParent() == null) || StringUtils.isEmpty(l.getParent().getName())) {
                categories.add(l.getName());
            }
        });

        final Map<String, List<String>> children = new HashMap<>();
        final List<AssetType> allType = this.assetTypeRepository.findAll().parallelStream()
                .filter(r -> r.getParent() != null).collect(Collectors.toList());
        allTypes.forEach(k -> {
            final List<AssetType> ll = allType.parallelStream().filter(r -> k.getId().equals(r.getParent().getId()))
                    .collect(Collectors.toList());
            final List<String> result = new ArrayList<>();
            ll.forEach(r -> {
                result.add(r.getName());
            });
            children.put(k.getName(), result);
        });
        final ArrayList<Integer> columns = Lists.newArrayList(DCAMConsts.ASSET_CONSTRAINT_CATEGORIED_COL,
                DCAMConsts.ASSET_CONSTRAINT_ASSET_TYPE_NAME_COL);
        EasyPoiExcelUtil.cascade(workbook, categories, categories,
                children,
                columns, 0, 1, DCAMConsts.ASSET_CONSTRAINT_ROW);

        EasyPoiExcelUtil.setConstraint(constraint, workbook, DCAMConsts.ASSET_START_CONSTRAINT_ROW,
                DCAMConsts.ASSET_CONSTRAINT_ROW);

        return workbook;

    }

    @Override
    public List<Asset> findByProduct(final Product product) {
        return this.assetRepository.findByProduct(product);
    }

    @Override
    public List<Asset> findByType(final AssetType type) {
        return this.assetRepository.findByType(type);
    }

    @Override
    public List<AssetDTO> indexAll(final Searchable searchable, final UserBean userBean) {
        final List<DcamInstitutionsDTO> institutions = this.dcamInstitutionsService.getPermInstitutions(userBean);
        final List<String> institutionCodeArray =
                institutions.stream().map(it -> it.getCode()).collect(Collectors.toList());
        searchable.put("submmitTo", institutionCodeArray);
        final List<Asset> models = this.assetRepository.search(searchable);
        return this.assetConventer.toListDTO(models);
    }

    @Override
    public Page<AssetDTO> search(final Pageable pageable, final Searchable searchable, final UserBean userBean) {
        final List<DcamInstitutionsDTO> institutions = this.dcamInstitutionsService.getPermInstitutions(userBean);
        final List<String> institutionCodeArray =
                institutions.stream().map(it -> it.getName()).collect(Collectors.toList());
        if (!(PermUtils.isExport(userBean) || PermUtils.isBackup(userBean) || PermUtils.isZongjian(userBean)
                || PermUtils.isAdmin(userBean))) {
            if (StringUtils.isEmpty(searchable.getStrValue("submmitTo"))) {
                searchable.put("submmitTo", institutionCodeArray);
            }
        }

        final Page<Asset> models = this.assetRepository.search(pageable, searchable);
        return this.assetConventer.toPageDTO(models);
    }

    @Override
    public List<DcamInstitutionsDTO> searchInstitution(final UserBean userBean) {
        final List<DcamInstitutionsDTO> institutions = this.dcamInstitutionsService.getPermInstitutionsByCode(userBean);
        return institutions;
    }

    @Override
    public void batchHandles(final Long[] ids) {
        try {
            for (final Long id : ids) {
                final Asset asset = this.assetRepository.getOne(id);
                asset.setStatus(DCAMConsts.ASSET_STATUS_SCRAP);
                this.assetRepository.save(asset);
            }
        } catch (final Exception e) {
            AssetServiceImpl.log.error(e.getMessage(), e);
            throw new UnitedException("部分资产已经产生业务，不能处置");
        }
    }

    @Override
    public String qrcodeFile(final Long[] ids) throws FileNotFoundException {
        final String uuid = UUID.randomUUID().toString();
        final Searchable searchable = new Searchable();
        searchable.put("ids", ids);
        final List<Asset> assets = new ArrayList<>();
        if ((ids != null) && (ids.length > 0)) {
            for (final Long id : ids) {
                assets.add(this.assetRepository.getOne(id));
            }
        }
        String outputDir = StringUtils.EMPTY;
        if (this.qrCodeConfig.getTemp().contains("classpath")) {
            final String classPath = ResourceUtils.getURL("classpath:").getPath();
            outputDir = this.qrCodeConfig.getTemp().replace("classpath:/", classPath) + File.separator
                    + "out" + File.separator + uuid;
        } else {
            outputDir = this.qrCodeConfig.getTemp() + File.separator + "out" + File.separator + uuid;
        }
        try {
            for (final Asset asset : assets) {
                final String outImg = outputDir + File.separator + asset.getId() + "tip.jpg";
                final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                final String manufacture =
                        asset.getManufacturerEndDate() == null ? "" : format.format(asset.getManufacturerEndDate());
                final String handoverDate =
                        asset.getHandoverDate() == null ? "" : format.format(asset.getHandoverDate());
                final String getDate = asset.getGetdate() == null ? "" : format.format(asset.getGetdate());
                final DecimalFormat numberFormat = new java.text.DecimalFormat("#,##0.00");
                final String money = asset.getMoney() == null ? "" : numberFormat.format(asset.getMoney());
                final String info =
                        "资产名称:" + asset.getName() + "" +
                                "\r\n存放地点:" + (asset.getLocated() == null ? "" : asset.getLocated() + "") +
                                "\r\n规格型号:" + (asset.getSpecification() == null ? "" : asset.getSpecification() + "") +
                                "\r\n账面原值（元）:" + money +
                                "\r\n取得日期:" + getDate + "" +
                                "\r\n维保截止日期:" + manufacture + "" +
                                "\r\n对应支撑的业务应用系:"
                                + (asset.getBusinessSystem() == null ? "" : asset.getBusinessSystem() + "") +
                                "\r\n对应的资产卡片编号:" + (asset.getOriginCode() == null ? "" : asset.getOriginCode() + "") +
                                "\r\n移交单位:" + (asset.getSubmmitTo() == null ? "" : asset.getSubmmitTo() + "") +
                                "\r\n移交日期" + handoverDate;
                this.qrCodeMaker.MakeQRCode(info, asset.getCode(), outImg);
            }
            PDFUtil.imagesToPdf(uuid, outputDir);
            PDFUtil.deleteFiles(outputDir);
        } catch (final WriterException e) {
            e.printStackTrace();
        } catch (final IOException e) {
            e.printStackTrace();
        }
        return outputDir + File.separator + uuid + ".pdf";
    }

    @Override
    public Workbook exportReport(Searchable searchable) {

        final NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(2);
        nf.setMinimumFractionDigits(2);
        final List<AssetDTO> result = this.findAll(searchable);

        result.forEach(asset -> {
            Date useDate = asset.getUsedate();
            if (null == useDate) {
                useDate = new Date();
            }
            useDate = DateUtils.round(useDate, Calendar.MONTH);
            final Date currentMonth = DateUtils.round(new Date(), Calendar.MONTH);
            final Calendar cal1 = Calendar.getInstance();
            cal1.setTime(useDate);
            final Calendar cal2 = Calendar.getInstance();
            cal2.setTime(currentMonth);

            final int duration = (((cal2.get(Calendar.YEAR) - cal1.get(Calendar.YEAR)) * 12) + cal2.get(Calendar.MONTH))
                    - cal1.get(Calendar.MONTH);

            Double month = asset.getMonth();
            if ((null == month) || (month == 0)) {
                month = 1.0;
            }
            Double money = asset.getMoney();
            if (null == money) {
                money = 0.0;
            }

            Double availableValue = money - ((money / month) * duration);
            if (availableValue < 0) {
                availableValue = 0.0;
            }
            asset.setExt5(nf
                    .format((new BigDecimal(availableValue)).setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue()));

        });

        final List<AssetValueReportVO> list = new ArrayList<>(result.size() == 0 ? 1 : result.size());
        result.stream().map(t -> {
            final AssetValueReportVO vo = new AssetValueReportVO();
            vo.setCode(t.getCode());
            vo.setAssetTypeName(t.getAssetTypeName());
            vo.setName(t.getName());
            vo.setSpecification(t.getSpecification());
            vo.setBrand(t.getBrand());
            vo.setSubmmitTo(t.getSubmmitTo());
            vo.setLocated(t.getLocated());
            vo.setUsedate(t.getUsedate());
            vo.setMonth(t.getMonth());
            vo.setMoney(
                    nf.format((new BigDecimal(t.getMoney())).setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue()));
            vo.setExt5(t.getExt5());
            return vo;
        }).forEach(list::add);

        final ExportParams param =
                new ExportParams("资产净值统计", "资产净值统计", ExcelType.XSSF);
        param.setStyle(EasyPoiStylerColorImpl.class);
        return ExcelExportUtil.exportExcel(param, AssetValueReportVO.class, list);
    }

    @Setter
    @Getter
    static class AssetValueReportVO {

        @Excel(name = "资产编号", orderNum = "0", width = 30)
        private Object code;

        @Excel(name = "资产分类", orderNum = "1", width = 30)
        private Object assetTypeName;

        @Excel(name = "资产名称", orderNum = "2", width = 40)
        private Object name;

        @Excel(name = "规格型号", orderNum = "3", width = 30)
        private Object specification;

        @Excel(name = "品牌", orderNum = "4", width = 30)
        private Object brand;

        @Excel(name = "所属厅局", orderNum = "5", width = 30)
        private Object submmitTo;

        @Excel(name = "存放地点", orderNum = "6", width = 30)
        private Object located;

        @Excel(name = "投入时间", orderNum = "7", width = 30)
        private Object usedate;

        @Excel(name = "年限", orderNum = "8", width = 30)
        private Object month;

        @Excel(name = "资产原值", orderNum = "9", width = 30)
        private Object money;

        @Excel(name = "资产净值", orderNum = "10", width = 30)
        private Object ext5;

    }

    @Override
    public Workbook exportMaintenanceReport(Searchable searchable) {
        final List<AssetDTO> result = this.findAll(searchable);

        final List<AssetMaintenanceReportVO> list = new ArrayList<>(result.size() == 0 ? 1 : result.size());
        result.stream().map(t -> {
            final AssetMaintenanceReportVO vo = new AssetMaintenanceReportVO();
            vo.setCode(t.getCode());
            vo.setAssetTypeName(t.getAssetTypeName());
            vo.setName(t.getName());
            vo.setSpecification(t.getSpecification());
            vo.setBrand(t.getBrand());
            vo.setSubmmitTo(t.getSubmmitTo());
            vo.setLocated(t.getLocated());
            vo.setUsedate(t.getUsedate());
            vo.setManufacturerEndDate(t.getManufacturerEndDate());
            return vo;
        }).forEach(list::add);

        final ExportParams param =
                new ExportParams("维保到期统计", "维保到期统计", ExcelType.XSSF);
        param.setStyle(EasyPoiStylerColorImpl.class);
        return ExcelExportUtil.exportExcel(param, AssetMaintenanceReportVO.class, list);
    }

    @Setter
    @Getter
    static class AssetMaintenanceReportVO {

        @Excel(name = "资产编号", orderNum = "0", width = 30)
        private Object code;

        @Excel(name = "资产分类", orderNum = "1", width = 30)
        private Object assetTypeName;

        @Excel(name = "资产名称", orderNum = "2", width = 40)
        private Object name;

        @Excel(name = "规格型号", orderNum = "3", width = 30)
        private Object specification;

        @Excel(name = "品牌", orderNum = "4", width = 30)
        private Object brand;

        @Excel(name = "所属厅局", orderNum = "5", width = 30)
        private Object submmitTo;

        @Excel(name = "存放地点", orderNum = "6", width = 30)
        private Object located;

        @Excel(name = "投入时间", orderNum = "7", width = 30)
        private Object usedate;

        @Excel(name = "维保到期时间", orderNum = "8", width = 30)
        private Object manufacturerEndDate;

    }

    @Override
    public boolean updateAssetRunningStatus(boolean status, Long[] ids) {
        for (final Long id : ids) {
            try {
                final Asset asset = this.assetRepository.getOne(id);
                asset.setRunning(status ? "YES" : "NO");
                this.assetRepository.save(asset);
            } catch (final EntityNotFoundException e) {
            }
        }
        return true;
    }

    @Override
    @Transactional
    public void lifeCycle(Long[] ids, String status) {
        try {
            for (final Long id : ids) {
                final Asset asset = this.assetRepository.getOne(id);
                asset.setStatus(status);
                this.assetRepository.save(asset);

                final AssetLifeCycle lc = this.assetLifeCycleConverter.toModel(asset);
                this.assetLifeCycleRepository.save(lc);
            }
        } catch (final Exception e) {
            AssetServiceImpl.log.error(e.getMessage(), e);
            throw new UnitedException("部分资产已经产生业务，不能改变");
        }

    }

    @Override
    public void addAttachment(AssetAttachmentDTO dto) {
        if (dto.isNew()) {
            final AssetAttachment attach = new AssetAttachment();
            attach.setDescription(dto.getDescription());
            attach.setAttachment(dto.getAttachment());
            if ((null != dto.getAssetId()) && (dto.getAssetId() > 0)) {
                final Optional<Asset> opt = this.assetRepository.findById(dto.getAssetId());
                if (opt.isPresent()) {
                    attach.setAsset(opt.get());
                }
            }
            this.assetAttachmentRepository.save(attach);
        } else {
            final Optional<AssetAttachment> opt = this.assetAttachmentRepository.findById(dto.getId());
            if (opt.isPresent()) {
                final AssetAttachment attach = opt.get();
                attach.setDescription(dto.getDescription());
                attach.setAttachment(dto.getAttachment());
                this.assetAttachmentRepository.save(attach);
            }
        }
    }

}
